package com.coocaa.x.provider;

import android.content.ContentValues;
import android.database.Cursor;
import android.database.MatrixCursor;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by lu on 15-12-2.
 */
public class ProviderData {
    /**
     * 所有要使用{@link ProviderData}中的接口T obj必须实现此接口，否则会抛出RuntimeException
     */
    public interface IProviderData {

    }

    private static final String FILED_TYPE_STRING = "java.lang.String";
    private static final String FILED_TYPE_INT = "int";
    private static final String FILED_TYPE_LONG = "long";
    private static final String FILED_TYPE_FLOAT = "float";
    private static final String FILED_TYPE_DOUBLE = "double";
    private static final String FILED_TYPE_BOOLEAN = "boolean";

    private static final String VALUECOLUMN_NAME = "value";
    private static final String[] VALUECOLUMNS = new String[]{VALUECOLUMN_NAME};

    public static Cursor toValueCursor(String value) {
        Object[] v = new String[]{value};
        MatrixCursor cur = new MatrixCursor(VALUECOLUMNS);
        cur.moveToFirst();
        cur.addRow(v);
        return cur;
    }

    public static String getValueCursorValue(Cursor c) {
        int columnIndex = c.getColumnIndex(VALUECOLUMN_NAME);
        if (columnIndex < 0)
            return null;
        return c.getString(columnIndex);
    }


    /**
     * @param list  需要转成Cursor的List对象
     * @param clazz 实现了{@link IProviderData}的class
     * @param <T>   实现了{@link IProviderData}的模板T
     * @return 转换成功的Cursor 如果失败会抛出RuntimeException
     */
    public static <T> Cursor listToCursor(List<T> list, Class<T> clazz) {
        if (!IProviderData.class.isAssignableFrom(clazz))
            throw new RuntimeException("The class " + clazz.getName() + " should implement IProviderData!!!");
        try {
            List<String> _columns = new ArrayList<String>();
            List<Object[]> _values = new ArrayList<Object[]>();
            Field[] fields = clazz.getDeclaredFields();

            //create columns
            for (Field field : fields) {
                if ((field.getModifiers() & Modifier.PRIVATE) == 0)
                    continue;
                field.setAccessible(true);
                String field_name = field.getName();
                _columns.add(field_name);
            }

            //get values
            if (list != null) {
                for (T t : list) {
                    List<String> values = new ArrayList<String>();
                    for (Field field : fields) {
                        if ((field.getModifiers() & Modifier.PRIVATE) == 0)
                            continue;
                        field.setAccessible(true);
                        String field_type = field.getType().toString();
                        if (field_type.contains(FILED_TYPE_STRING)) {
                            values.add((String) field.get(t));
                        } else if (field_type.contains(FILED_TYPE_LONG)) {
                            values.add(String.valueOf(field.get(t)));
                        } else if (field_type.contains(FILED_TYPE_DOUBLE)) {
                            values.add(String.valueOf(field.get(t)));
                        } else if (field_type.contains(FILED_TYPE_INT)) {
                            values.add(String.valueOf(field.get(t)));
                        } else if (field_type.contains(FILED_TYPE_FLOAT)) {
                            values.add(String.valueOf(field.get(t)));
                        } else if (field_type.contains(FILED_TYPE_BOOLEAN)) {
                            values.add(String.valueOf(field.get(t)));
                        }
                    }
                    _values.add(values.toArray());
                }
            }

            String[] columns = new String[_columns.size()];
            columns = _columns.toArray(columns);
            MatrixCursor cur = new MatrixCursor(columns);
            cur.moveToFirst();
            for (Object[] _value : _values)
                cur.addRow(_value);
            return cur;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * @param c     需要转换成List的Cursor对象
     * @param clazz 实现了{@link IProviderData}的class
     * @param <T>   实现了{@link IProviderData}的模板T
     * @return 转换成功的List 如果失败会抛出RuntimeException
     */
    public static <T> List<T> listFromCursor(Cursor c, Class<T> clazz) {
        if (!IProviderData.class.isAssignableFrom(clazz))
            throw new RuntimeException("The class " + clazz.getName() + " should implement IProviderData!!!");
        if (c.moveToFirst()) {
            List<T> list = new ArrayList<T>();
            do {
                T t = objectFromCursor(c, clazz);
                if (t != null)
                    list.add(t);
            } while (c.moveToNext());
            return list;
        }
        return null;
    }

    /**
     * @param c     需要转换成T的Cursor对象
     * @param clazz 实现了{@link IProviderData}的class
     * @param <T>   实现了{@link IProviderData}的模板T
     * @return 转换成功的T对象 如果失败会抛出RuntimeException
     */
    public static <T> T objectFromCursor(Cursor c, Class<T> clazz) {
        if (!IProviderData.class.isAssignableFrom(clazz))
            throw new RuntimeException("The class " + clazz.getName() + " should implement IProviderData!!!");
        try {
            T t = clazz.newInstance();
            t = getClassFields(c, t, clazz);
            return t;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private static <T> T getClassFields(Cursor c, T t, Class<?> clazz) throws Exception {
        Class<?> _clazz = clazz;
        do {
            Field[] fields = _clazz.getDeclaredFields();
            for (Field field : fields) {// --for() begin
                if ((field.getModifiers() & Modifier.PRIVATE) == 0)
                    continue;
                field.setAccessible(true);
                String field_name = field.getName().toLowerCase();
                String field_type = field.getType().toString();
                int columnIndex = c.getColumnIndex(field_name);
                if (columnIndex < 0)
                    continue;
                if (field_type.contains(FILED_TYPE_STRING)) {
                    field.set(t, c.getString(columnIndex));
                } else if (field_type.contains(FILED_TYPE_LONG)) {
                    field.set(t, c.getLong(columnIndex));
                } else if (field_type.contains(FILED_TYPE_DOUBLE)) {
                    field.set(t, c.getDouble(columnIndex));
                } else if (field_type.contains(FILED_TYPE_INT)) {
                    field.set(t, c.getInt(columnIndex));
                } else if (field_type.contains(FILED_TYPE_FLOAT)) {
                    field.set(t, c.getFloat(columnIndex));
                } else if (field_type.contains(FILED_TYPE_BOOLEAN)) {
                    field.set(t, Boolean.valueOf(c.getString(columnIndex)));
                }
            }
            _clazz = _clazz.getSuperclass();
        } while (_clazz != null);
        return t;
    }

    /**
     * @param t     需要转换成Cursor的T对象
     * @param clazz 实现了{@link IProviderData}的class
     * @param <T>   实现了{@link IProviderData}的模板T
     * @return 转换成功的Cursor对象 如果失败会抛出RuntimeException
     */
    public static <T> Cursor objectToCursor(T t, Class<T> clazz) {
        if (!IProviderData.class.isAssignableFrom(clazz))
            throw new RuntimeException("The class " + clazz.getName() + " should implement IProviderData!!!");
        try {
            List<String> _columns = new ArrayList<String>();
            Field[] fields = clazz.getDeclaredFields();

            //create columns
            for (Field field : fields) {
                if ((field.getModifiers() & Modifier.PRIVATE) == 0)
                    continue;
                field.setAccessible(true);
                String field_name = field.getName();
                _columns.add(field_name);
            }

            //get values
            List<String> values = new ArrayList<String>();
            for (Field field : fields) {
                if ((field.getModifiers() & Modifier.PRIVATE) == 0)
                    continue;
                field.setAccessible(true);
                String field_type = field.getType().toString();
                if (field_type.contains(FILED_TYPE_STRING)) {
                    values.add((String) field.get(t));
                } else if (field_type.contains(FILED_TYPE_LONG)) {
                    values.add(String.valueOf(field.get(t)));
                } else if (field_type.contains(FILED_TYPE_DOUBLE)) {
                    values.add(String.valueOf(field.get(t)));
                } else if (field_type.contains(FILED_TYPE_INT)) {
                    values.add(String.valueOf(field.get(t)));
                } else if (field_type.contains(FILED_TYPE_FLOAT)) {
                    values.add(String.valueOf(field.get(t)));
                } else if (field_type.contains(FILED_TYPE_BOOLEAN)) {
                    values.add(String.valueOf(field.get(t)));
                }
            }


            String[] columns = new String[_columns.size()];
            columns = _columns.toArray(columns);
            MatrixCursor cur = new MatrixCursor(columns);
            cur.moveToFirst();
            cur.addRow(values.toArray());
            return cur;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * @param obj 需要转换成ContentValues obj，此obj需要实现{@link IProviderData}
     * @return 转换成功的ContentValues， 如果失败会抛出RuntimeException
     */
    public static ContentValues toContentValues(Object obj) {
        if (!IProviderData.class.isInstance(obj))
            throw new RuntimeException("The class " + obj.getClass().getName() + " should implement IProviderData!!!");
        try {
            ContentValues cv = new ContentValues();
            Field[] fields = obj.getClass().getDeclaredFields();
            for (Field field : fields) {// --for() begin
                if ((field.getModifiers() & Modifier.PRIVATE) == 0)
                    continue;
                field.setAccessible(true);
                String field_name = field.getName();
                String field_type = field.getType().toString();
                if (field_type.contains(FILED_TYPE_STRING)) {
                    cv.put(field_name, (String) field.get(obj));
                } else if (field_type.contains(FILED_TYPE_LONG)) {
                    cv.put(field_name, (Long) field.get(obj));
                } else if (field_type.contains(FILED_TYPE_DOUBLE)) {
                    cv.put(field_name, (Double) field.get(obj));
                } else if (field_type.contains(FILED_TYPE_INT)) {
                    cv.put(field_name, (Integer) field.get(obj));
                } else if (field_type.contains(FILED_TYPE_FLOAT)) {
                    cv.put(field_name, (Float) field.get(obj));
                } else if (field_type.contains(FILED_TYPE_BOOLEAN)) {
                    cv.put(field_name, (Boolean) field.get(obj));
                }
            }
            return cv;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
